﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using AMM.Business;
using AMM.Business.Config;
using AMM.Business.Project;
using AMM.Business.Store;
using AMM.Model;
using AMM.Model.Project;
using AMM.Model.Store;

namespace AMM.Forms.Store {
    public partial class FrmGenerateProcurementOrder : FrmRootBase {

        private List<MidProcurementOrder> _midList;
        private List<VendorViewModel> _vendorList;
        private VendorProcessor _vendorProcessor;
        private QuotationProcessor _quotationProcessor;
        private ProcurementOrderProcessor _procurementOrderProcessor;

        protected override string FunctionCode {
            get { return "AMM1405"; }
        }

        public FrmGenerateProcurementOrder() {
            this.InitializeComponent();

            this.BindSource();
            this.BindMaterial();
            this.BindVendor();
        }

        #region Private methods

        private void BindSource() {
            this.Source.DataSource = new BasicsProcessor().FetchEnabledBasicsByType(BasicsType.ProcurementSourceType);
            this.Source.DisplayMember = "Name";
            this.Source.ValueMember = "BasicsId";
        }

        private void BindMaterial() {
            MaterialSearchModel searchModel = new MaterialSearchModel() { IsEnabled = true };
            MaterialProcessor materialProcessor = new MaterialProcessor(int.MaxValue);
            List<MaterialViewModel> materialList = materialProcessor.FetchMaterialViewModelList(searchModel);

            this.Material.DisplayMemberEx = "Code";
            this.Material.ValueMemberEx = "Key";
            this.Material.HeightEx = 300;
            this.Material.WidthEx = 400;
            this.Material.PageSizeEx = 20;
            this.Material.DataBind(new MaterialViewModel(), x => new { x.MaterialType, x.Code, x.Name, x.Remarks }, materialList);
        }

        private void BindVendor(List<Vendor> vendors) {
            List<VendorViewModel> vendorList = new List<VendorViewModel>();
            vendors.ForEach(x => {
                vendorList.Add(new VendorViewModel() {
                    Key = x.VendorId,
                    Code = x.Code,
                    Name = x.Name,
                    NameExtend = x.NameExtend,
                    Address = x.Address,
                    Linkman = x.Linkman,
                    Phone = x.Phone,
                    Purchaser = x.User.Name,
                    PayCurrency = x.Basic.Code,
                    VendorStatus = x.Basic1.Code,
                    VendorType = x.Basic2.Code,
                    Remarks = x.Remarks,
                    PayCondition = x.PayCondition,
                    IncreaseRate = x.IncreaseRate,
                    InvoiceRate = x.InvoiceRate,
                    Fax = x.Fax,
                    Email = x.Email,
                    IsEnabled = x.IsEnabled,
                    IsAttach = x.AttachmentId.HasValue,
                    CreatedBy = x.CreatedBy,
                    CreatedDatetime = x.CreatedDatetime,
                    ModifiedBy = x.ModifiedBy,
                    ModifiedDatetime = x.ModifiedDatetime
                });
            });

            this.Vendor.DisplayMemberEx = "Code";
            this.Vendor.ValueMemberEx = "Key";
            this.Vendor.HeightEx = 300;
            this.Vendor.WidthEx = 400;
            this.Vendor.PageSizeEx = 20;
            this.Vendor.DataBind(new VendorViewModel(), x => new { x.Code, x.Name, x.Address }, vendorList);
        }

        private void BindVendor() {
            VendorSearchModel searchModel = new VendorSearchModel() { IsEnabled = true };
            this._vendorProcessor = new VendorProcessor();
            if (this._vendorList == null || this._vendorList.Count == 0) {
                this._vendorList = _vendorProcessor.FetchVendorViewModelList(searchModel);
            }

            this.Vendor.DisplayMemberEx = "Code";
            this.Vendor.ValueMemberEx = "Key";
            this.Vendor.HeightEx = 300;
            this.Vendor.WidthEx = 400;
            this.Vendor.PageSizeEx = 20;
            this.Vendor.DataBind(new VendorViewModel(), x => new { x.Code, x.Name, x.Address }, _vendorList);
        }

        private void BindDataGridView() {
            this.CreateNewThread(() => {
                this._midList = this._procurementOrderProcessor.GenerateProdurementOrder();
            }, () => {
                this.dgvEdit.DataSourceEx = this._midList;
                this.tsBtnSave.Enabled = this._midList.Count > 0 && !this._midList.Any(x => !x.IsValid);
            });
        }

        private void Save() {
            this.CreateNewThread(() => {
                string autoCode = CommonHelper.GenerateAutoCode("R");
                int i = this._procurementOrderProcessor.GetTheMaxFlowNumber(autoCode);
                List<ProcurementOrder> procurementOrderList = new List<ProcurementOrder>();
                this._midList.GroupBy(x => x.VendorId.Value, (key, ms) => new { VendorId = key, Total = ms.Count() })
                    .ToList().ForEach(x => {
                        ProcurementOrder procurementOrder = new ProcurementOrder();
                        procurementOrder.ProcurementOrderId = Guid.NewGuid().GetHashCode();
                        procurementOrder.Code = CommonHelper.GendrateSpecificCode(autoCode, i);
                        procurementOrder.VendorId = x.VendorId;
                        procurementOrder.Status = (int)AuditStatus.Waiting;
                        procurementOrder.CreatedBy = LoginUserName;
                        procurementOrder.CreatedDatetime = DateTime.Now;
                        this._midList.Where(y => y.VendorId.Value == x.VendorId).ToList().ForEach(y => {
                            y.ProcurementOrderId = procurementOrder.ProcurementOrderId;
                            ProcurementOrderDetail existProcurementOrderDetail = procurementOrder.ProcurementOrderDetails
                                .FirstOrDefault(z => z.MaterialId == y.MaterialId.Value);
                            if (existProcurementOrderDetail != null) {
                                existProcurementOrderDetail.Quantity += Math.Ceiling(y.Quantity.Value);
                            }
                            else {
                                ProcurementOrderDetail procurementOrderDetail = new ProcurementOrderDetail();
                                procurementOrderDetail.ProcurementOrderDetailsId = Guid.NewGuid().GetHashCode();
                                procurementOrderDetail.ProcurementOrderId = procurementOrder.ProcurementOrderId;
                                procurementOrderDetail.MaterialId = y.MaterialId.Value;
                                procurementOrderDetail.SourceId = y.SourceId.Value;
                                procurementOrderDetail.Quantity = Math.Ceiling(y.Quantity.Value);
                                procurementOrderDetail.DeliveryDate = y.DeliveryDate.Value;
                                procurementOrderDetail.Price = y.Price.Value;
                                procurementOrderDetail.CreatedBy = LoginUserName;
                                procurementOrderDetail.CreatedDatetime = DateTime.Now;
                                procurementOrder.ProcurementOrderDetails.Add(procurementOrderDetail);
                            }

                        });
                        procurementOrderList.Add(procurementOrder);
                        i++;
                    });

                this._procurementOrderProcessor.SaveGeneratedProdurementOrder(procurementOrderList, this._midList);
            }, () => {
                this.BindDataGridView();
                this.ShowInfo("保存成功");
            });

        }

        #endregion

        private void FrmGenerateProcurementOrder_Load(object sender, EventArgs e) {
            this._procurementOrderProcessor = new ProcurementOrderProcessor();
            this._quotationProcessor = new QuotationProcessor();
            this._midList = new List<MidProcurementOrder>();

            this.WindowState = FormWindowState.Maximized;
            this.dgvEdit.ContextMenuStrip = null;

            this.BindDataGridView();
        }

        private void dgvEdit_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e) {
            if (this.dgvEdit.Columns[e.ColumnIndex].Name == "Vendor") {
                MidProcurementOrder midpo = (MidProcurementOrder)(this.dgvEdit.Rows[e.RowIndex].DataBoundItem);
                this.BindVendor(midpo.Vendors);
            }
        }

        private void dgvEdit_CellEndEdit(object sender, DataGridViewCellEventArgs e) {
            if (this.dgvEdit.Columns[e.ColumnIndex].Name == "Vendor") {
                this.BindVendor();
            }
        }

        private void dgvEdit_CellValueChanged(object sender, DataGridViewCellEventArgs e) {
            if (e.RowIndex == -1) { return; }
            MidProcurementOrder currentMPO = (MidProcurementOrder)this.dgvEdit.Rows[e.RowIndex].DataBoundItem;
            Quotation quotion = this._quotationProcessor.FetchQuotationByVendorIdAndMaterialId(
                currentMPO.VendorId.Value, currentMPO.MaterialId.Value);
            currentMPO.Price = quotion.IsMultiple
                ? currentMPO.Quantity > quotion.PriceThresholdValue ? quotion.PriceGreaterThan : quotion.Price
                : quotion.Price;
            currentMPO.Total = currentMPO.Quantity * currentMPO.Price;
            currentMPO.DeliveryDate = DateTime.Now.AddDays(quotion.PreProcurementCycle + quotion.ProcurementCycle);
            this._midList[e.RowIndex] = currentMPO;
            this.dgvEdit.DataSourceEx = this._midList;
        }

        private void tsBar_ItemClicked(object sender, ToolStripItemClickedEventArgs e) {
            switch (e.ClickedItem.Name) {
                case "tsBtnReload": this.BindDataGridView(); break;
                case "tsBtnSave": this.Save(); break;
                case "tsBtnQuit": this.Close(); break;
            }
        }
    }
}
